"""
定时更新全部的端口流量图表
"""

import os
import re
import sys
import json
from django import setup
from pathlib import Path

# 将项目路径添加到系统搜寻路径当中，查找方式为从当前脚本开始，找到要调用的django项目的路径
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent))
sys.path.insert(0, str(Path(__file__).resolve().parent.parent.parent.parent))

os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_site.settings')
setup()

from apps.app_net_flow.models import ChartModel
from apps.app_net_flow.models import Menu2Chart
from apps.app_global.task_locks import netflow_update_element_lock
from django.utils import timezone as dj_timezone
from datetime import timedelta
from apps.app_alert.utils.utils import DateUtils
from apps.app_alert.utils.logger import setup_logger
from apps.app_alert.utils.utils import download
from django.conf import settings

logger = setup_logger(__name__, __file__)


class NetBackend(object):
    AUTH = settings.EASY_OPS.get('AUTH')

    def get_node_list(self):
        url = 'https://netbackend.cstcloud.cn/api/v3/model-factory/tree/nodes-contain-instance-by-relation-end/uplink/port'
        resp = download(method="get", url=url, auth=self.AUTH)
        text = resp.text
        node_id_list = re.findall('"id":"(.*?)"', text)
        return node_id_list

    def get_source_list(self):
        interface_mapping = dict()
        for node_id in self.get_node_list():
            node_source_items = self.get_node_source_list(node_id=node_id)
            for item in node_source_items:
                item.pop('if_index', '')
                device_ip = item.get("device_ip")
                port_name = item.get("port_name")
                ip_port_str = f'{device_ip}_{port_name}'
                if not interface_mapping.get(ip_port_str):
                    interface_mapping[ip_port_str] = list()
                interface_mapping[ip_port_str].append(item)
        result = list()
        for k, v in interface_mapping.copy().items():
            sorted_v = sorted(v, key=lambda x: x['class_name'])
            result.append(sorted_v[0])
        return result

    def get_node_source_list(self, node_id):
        results = list()
        url = f'https://netbackend.cstcloud.cn/api/v3/mrtg/mrtg/instance-ports-in-tree-node/{node_id}/?limit=50'
        while True:
            logger.info(url)
            resp = download(method="get", url=url, auth=self.AUTH)
            text = resp.text
            text = json.loads(text)
            next_page_url = text.get("next")
            page_results = text.get("results")
            results.extend(page_results)
            if next_page_url:
                url = next_page_url
            else:
                break
        return results


def update_elements():
    logger.info(f"当前时间：{DateUtils.now()}")
    chart_list = NetBackend().get_source_list()
    element_set = set()
    for item in chart_list:
        obj, created = ChartModel.objects.update_or_create(
            device_ip=item.get("device_ip"),
            port_name=item.get("port_name"),
            defaults=item
        )
        element_set.add(f'{item.get("device_ip")}_{item.get("port_name")}')
        logger.info(obj)
        logger.info(created)
    queryset = ChartModel.objects.all()
    for item in queryset:
        ip_port = f'{item.device_ip}_{item.port_name}'
        if ip_port not in element_set:
            menu2chart_queryset = Menu2Chart.objects.filter(chart=item)
            menu2chart_queryset.delete()
            item.delete()


def run_task_use_lock():
    nt = dj_timezone.now()
    ok, exc = netflow_update_element_lock.acquire(expire_time=(nt + timedelta(minutes=20)))  # 先拿锁
    if not ok:  # 未拿到锁退出
        return

    run_desc = 'success'
    try:
        # 成功拿到锁后，各定时任务根据锁的上周期任务执行开始时间 “lock.start_time”判断 当前任务是否需要执行（本周期其他节点可能已经执行过了）
        if (
                not netflow_update_element_lock.start_time
                or (nt - netflow_update_element_lock.start_time) >= timedelta(minutes=20)  # 定时周期
        ):
            netflow_update_element_lock.mark_start_task()  # 更新任务执行信息
            update_elements()
    except Exception as exc:
        run_desc = str(exc)
    finally:
        ok, exc = netflow_update_element_lock.release(run_desc=run_desc)  # 释放锁
        # 锁释放失败，发送通知
        if not ok:
            netflow_update_element_lock.notify_unrelease()


if __name__ == '__main__':
    run_task_use_lock()
    # update_elements()

